import { EventTarget, sys } from 'cc';
import { PREVIEW } from 'cc/env';

/**
 * Cocos Creator 的全局事件拓展
 * 备注：抛事件和监听事件需要同一个EventTarget对象才能实现抛接。
 */
export default class EventExt {

    private _ccevent: EventTarget = null;
    private constructor() {
        this._ccevent = new EventTarget();
    };
    private static _ins: EventExt = null;
    private static getIns(): EventExt {
        if (!EventExt._ins) {
            EventExt._ins = new EventExt();
        }
        return EventExt._ins;
    }

    /**
     * 注册事件目标的特定事件类型回调。这种类型的事件应该被 `emit` 触发。
     * @param type - A string representing the event type to listen for.
     * @param callback - The callback that will be invoked when the event is dispatched.
     *                              The callback is ignored if it is a duplicate (the callbacks are unique).
     * @param thisArg - The target (this object) to invoke the callback, can be null
     * @return - Just returns the incoming callback so you can save the anonymous function easier.
     * @example
     * eventTarget.on('fire', function () {
     *     log("fire in the hole");
     * }, node);
     */
    static on<TFunction extends (...any: any[]) => void>(type: string | number, callback: TFunction, thisArg?: any, once?: boolean): typeof callback {
        const evt = EventExt.getIns()._ccevent;
        return evt.on(type, callback, thisArg, once);
    }

    /**
     * 删除之前用同类型，回调，目标或 useCapture 注册的事件监听器，如果只传递 type，将会删除 type 类型的所有事件监听器。
     * @param type - A string representing the event type being removed.
     * @param callback - The callback to remove.
     * @param target - The target (this object) to invoke the callback, if it's not given, only callback without target will be removed
     * @example
     * // register fire eventListener
     * var callback = eventTarget.on('fire', function () {
     *     log("fire in the hole");
     * }, target);
     * // remove fire event listener
     * eventTarget.off('fire', callback, target);
     * // remove all fire event listeners
     * eventTarget.off('fire');
     */
    static off<TFunction extends (...any: any[]) => void>(type: string | number, callback?: TFunction, thisArg?: any): void {
        const evt = EventExt.getIns()._ccevent;
        evt.off(type, callback, thisArg);
    }

    /**
     * 在当前 EventTarget 上删除指定目标（target 参数）注册的所有事件监听器。
     * 这个函数无法删除当前 EventTarget 的所有事件监听器，也无法删除 target 参数所注册的所有事件监听器。
     * 这个函数只能删除 target 参数在当前 EventTarget 上注册的所有事件监听器。
     * @param typeOrTarget - The target to be searched for all related listeners
     */
    static targetOff(typeOrTarget: any): void {
        const evt = EventExt.getIns()._ccevent;
        evt.targetOff(typeOrTarget);
    }

    /**
     * 派发一个指定事件，并传递需要的参数
     * @param type - event type
     * @param arg - Arguments when the event triggered
     */
    static emit(type: string | number, arg0?: any, arg1?: any, arg2?: any, arg3?: any, arg4?: any): void {
        const evt = EventExt.getIns()._ccevent;
        PREVIEW && sys.isBrowser && console.log(`[EventExt] emit event, type:${type}, arg0:${arg0}, arg1:${arg1}, arg2:${arg2}, arg3:${arg3}, arg4:${arg4}`);
        evt.emit(type, arg0, arg1, arg2, arg3, arg4);
    }

}